package com.fu.mr.bluetoothdchat;

import android.app.ProgressDialog;
import android.arch.lifecycle.Observer;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.fu.mr.bluetoothdchat.thread.AcceptThread;
import com.fu.mr.bluetoothdchat.thread.CommunicateThread;
import com.fu.mr.bluetoothdchat.thread.ConnectThread;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * <pre>
 *     author : Mr.Fu
 *     e-mail : 18622268981@163.com
 *     time   : 2020/03/06
 *     desc   : 主界面(聊天界面)
 *              待实现功能:
 *                 1.   自定义标题栏,添加选项菜单按钮
 *                 2    选项菜单:  首选项(类似设置功能), 设备信息查看(蓝牙地址), 保存上下文, 清理视图
 *                      允许被查找等
 *                 3.   使用自定义对话框替换系统进度条对话框
 *
 *     version: 1.0     实现蓝牙设备连接,数据传输(聊天)功能
 * </pre>
 */

public class MainActivity extends AppCompatActivity implements AcceptThread.AcceptListener,
        ConnectThread.ConnectListener,
        CommunicateThread.CommunicateListener {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int REQUEST_CODE_OPEN_BLUETOOTH = 101;

    private TextView mTvConnectState;
    private ImageView mIvOptionMenu;
    private TextView mTvTip;
    private RecyclerView mChatListView;
    private EditText mEtMessage;
    private Button mBtnSend;
    private ProgressDialog mProgressDialog;

    private boolean mIsConnected = false;
    private boolean mIsExit = false;
    //  是否主动断开连接
    private boolean mIsActiveDisconnected = false;
    private ChatListAdapter mChatListAdapter;
    //  聊天数据集合
    private List<ChatListModel> mChatList = new ArrayList<>();
    private BluetoothReceiver mBluetoothReceiver;

    private BluetoothSocket mSocket;
    private BluetoothManager mBluetoothManager;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnectThread;
    private CommunicateThread mCommunicateThread;

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {

            if (msg.what == 0) {
                byte[] readBuf = (byte[]) msg.obj;
                String readMessage = new String(readBuf, 0, msg.arg1);
                Log.d(TAG, "readMessage= " + readMessage);
                addLeftText(readMessage);
            }
            return false;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
    }

    @Override
    public void onAccept(BluetoothSocket socket, final BluetoothDevice device) {

        mSocket = socket;
        Log.d(TAG, "onAccept: 被动连接成功, 已连接: " + device.getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                refreshConnectStatus(true, "已连接: " + device.getName());
            }
        });
        startCommunicationTask(socket);
        cancelAcceptTask();
    }

    @Override
    public void onConnected(BluetoothSocket socket, final BluetoothDevice device) {

        Log.d(TAG, "onConnected -> 主动连接成功: " + device.getName());
        hideConnectProgressDialog();
        mSocket = socket;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                refreshConnectStatus(true, "已连接: " + device.getName());
            }
        });
        startCommunicationTask(socket);
        cancelAcceptTask();
    }

    @Override
    public void onConnectFailed() {

        Log.e(TAG, "onConnectFailed -> 设备连接失败");
        hideConnectProgressDialog();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                refreshConnectStatus(false, "设备连接失败");
            }
        });
        cancelConnectTask();
    }

    @Override
    public void onConnectionLost() {

        Log.d(TAG, "onReadIOException: 连接丢失/断开 ");
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (!BluetoothManager.getInstance().isEnabled()) {
                    refreshConnectStatus(false, "蓝牙已关闭");
                } else {
                    if (mIsActiveDisconnected) {
                        refreshConnectStatus(false, "设备连接已断开");
                        mIsActiveDisconnected = false;
                    } else {
                        refreshConnectStatus(false, "设备连接已丢失");
                    }
                }
            }
        });
        cancelAllTask();
        if (!mIsExit) {
            startAcceptTask();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (requestCode == REQUEST_CODE_OPEN_BLUETOOTH) {
            if (resultCode == RESULT_OK) {
                showToastMessage("允许本地蓝牙被附近的其它蓝牙设备发现");
                mTvConnectState.setEnabled(true);
            } else if (resultCode == RESULT_CANCELED) {
                showToastMessage("不允许蓝牙被附近的其它蓝牙设备发现");
                mTvConnectState.setEnabled(false);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        Log.d(TAG, "onDestroy");
        mIsExit = true;
        // 2020/3/10 注销蓝牙相关广播
        unregisterBluetoothReceiver();
        cancelAllTask();
    }

    private void initView() {

        mTvConnectState = findViewById(R.id.tv_connect_state);
        mIvOptionMenu = findViewById(R.id.iv_option_menu);
        mTvTip = findViewById(R.id.tv_tip);
        mEtMessage = findViewById(R.id.et_message);
        mTvConnectState.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (!mIsConnected) {
                    Intent intent = DevicesListActivity.getCallingIntent(MainActivity.this);
                    startActivity(intent);
                } else {
                    mIsActiveDisconnected = true;
                    cancelCommunicateTask();
                }
            }
        });

        mChatListView = findViewById(R.id.rv_chat);
        mChatListView.setLayoutManager(new LinearLayoutManager(this));
        mChatListAdapter = new ChatListAdapter(this, mChatList);
        mChatListView.setAdapter(mChatListAdapter);

        mBtnSend = findViewById(R.id.btn_send);
        mBtnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String message = mEtMessage.getText().toString().trim();
                sendMessage(message);
                mEtMessage.setText("");
            }
        });
    }

    private void initData() {

        mBluetoothManager = BluetoothManager.getInstance();
        if (!mBluetoothManager.isSupported()) {
            showToastMessage("当前设备不支持蓝牙");
            mTvConnectState.setEnabled(false);
            return;
        }

        if (mBluetoothManager.isEnabled()) {
            mTvConnectState.setEnabled(true);
            refreshConnectStatus(false, "蓝牙已开启");
        } else {
            mTvConnectState.setEnabled(false);
            refreshConnectStatus(false, "蓝牙未开启");
            mBluetoothManager.open(MainActivity.this, REQUEST_CODE_OPEN_BLUETOOTH);
        }

        startAcceptTask();

        registerBluetoothReceiver();

        LiveDataBus.get().with("KEY_BLUETOOTH_DEVICE", BluetoothDevice.class)
                .observe(this, new Observer<BluetoothDevice>() {
                    @Override
                    public void onChanged(@Nullable final BluetoothDevice device) {

                        Log.w(TAG, "The address of device is " + device.getAddress());
                        // 执行连接设备操作
                        startConnectTask(device);
                    }
                });
    }

    /**
     * 开启监听外来蓝牙连接请求的线程
     */
    private void startAcceptTask() {

        if (BluetoothManager.getInstance().isEnabled()) {
            if (mAcceptThread == null) {
                mAcceptThread = new AcceptThread(true);
                mAcceptThread.setAcceptListener(this);
                mAcceptThread.start();
            }
        }
    }

    /**
     * 取消(关闭)监听外来蓝牙连接请求的线程
     */
    private void cancelAcceptTask() {

        if (mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
    }

    /**
     * 开启主动连接蓝牙的线程
     *
     * @param device
     */
    private void startConnectTask(BluetoothDevice device) {

        showConnectProgressDialog(device.getName());
        if (mConnectThread == null) {
            mConnectThread = new ConnectThread(device);
        }
        mConnectThread.setConnectListener(this);
        mConnectThread.start();
    }

    /**
     * 取消(关闭)主动连接蓝牙的线程
     */
    private void cancelConnectTask() {

        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
    }

    /**
     * 开启蓝牙设备之间的通讯(数据传输)线程
     *
     * @param socket
     */
    private void startCommunicationTask(BluetoothSocket socket) {

        if (mCommunicateThread == null) {
            mCommunicateThread = new CommunicateThread(socket, mHandler);
        }
        mCommunicateThread.setCommunicateListener(this);
        mCommunicateThread.start();
    }

    /**
     * 取消(关闭)蓝牙设备之间的通讯(数据传输)线程
     */
    private void cancelCommunicateTask() {

        if (mCommunicateThread != null) {
            mCommunicateThread.cancel();
            mCommunicateThread = null;
        }
    }

    /**
     * 取消(关闭)所有与蓝牙相关的线程
     */
    private void cancelAllTask() {

        Log.d(TAG, "cancelAllTask");
        mSocket = null;
        cancelAcceptTask();
        cancelConnectTask();
        cancelCommunicateTask();
    }

    /**
     * 注册蓝牙相关广播
     */
    private void registerBluetoothReceiver() {

        if (mBluetoothReceiver == null) {
            mBluetoothReceiver = new BluetoothReceiver();
        }
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_OFF");
        intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_ON");

        registerReceiver(mBluetoothReceiver, intentFilter);
    }

    /**
     * 注销蓝牙相关广播
     */
    private void unregisterBluetoothReceiver() {

        if (mBluetoothReceiver != null) {
            unregisterReceiver(mBluetoothReceiver);
            mBluetoothReceiver = null;
        }
    }

    /**
     * 发送消息(数据)
     *
     * @param message
     */
    private void sendMessage(final String message) {

        if (!mIsConnected || mSocket == null) {
            showToastMessage("请先连接设备!");
            return;
        }

        if (!TextUtils.isEmpty(message)) {
            byte[] msg = message.getBytes();
            try {
                mSocket.getOutputStream().write(msg);
            } catch (IOException e) {
                e.printStackTrace();
                showToastMessage("发送消息失败!");
                return;
            }
            addRightText(new String(msg).toString());
        } else {
            showToastMessage("发送消息不能为空");
            String msg2 = readAssetResource(this, "1800ADData.txt");
            byte[] msg = msg2.getBytes();
            try {
                mSocket.getOutputStream().write(msg);
            } catch (IOException e) {
                e.printStackTrace();
                showToastMessage("发送消息失败!");
                return;
            }
        }
    }

    /**
     * 读取 assets 文件夹下的 fileName 文件的内容,并转变为 String 类型数据的方法
     *
     * @param context
     * @param fileName
     * @return
     */
    private String readAssetResource(Context context, String fileName) {

        AssetManager assetManager = context.getAssets();
        String srtResponse = "";

        try {
            InputStream is = assetManager.open(fileName);
            srtResponse = getStringFromInputStream(is);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return srtResponse;
    }

    /**
     * 从输入流中获取 String 类型数据
     *
     * @param inputStream
     * @return
     */
    private String getStringFromInputStream(InputStream inputStream) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;

        try {
            br = new BufferedReader(new InputStreamReader(inputStream));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();
    }

    /**
     * 添加接收数据(消息)并刷新UI界面消息列表
     *
     * @param message
     */
    private void addLeftText(String message) {

        ChatListModel model = new ChatListModel();
        model.setType(ChatListAdapter.LEFT);
        model.setLeftText(message);
        mChatList.add(model);
        mChatListAdapter.notifyDataSetChanged();
        // 2020/3/20 实现添加数据后自动滑动到列表底部的功能
        mChatListView.scrollToPosition(mChatListAdapter.getItemCount() - 1);
    }

    /**
     * 添加发送数据(消息)并刷新UI界面消息列表
     *
     * @param message
     */
    private void addRightText(String message) {

        ChatListModel model = new ChatListModel();
        model.setType(ChatListAdapter.RIGHT);
        model.setRightText(message);
        mChatList.add(model);
        mChatListAdapter.notifyDataSetChanged();
        // 2020/3/20 实现添加数据后自动滑动到列表底部的功能
        mChatListView.scrollToPosition(mChatListAdapter.getItemCount() - 1);
    }

    /**
     * 刷新 UI 界面蓝牙连接状态
     *
     * @param isConnected
     * @param hintText
     */
    private void refreshConnectStatus(boolean isConnected, String hintText) {

        if (isConnected) {
            mTvConnectState.setText("断开");
            mTvTip.setTextColor(Color.BLUE);
            mIvOptionMenu.setVisibility(View.VISIBLE);
        } else {
            mTvConnectState.setText("连接");
            mIvOptionMenu.setVisibility(View.GONE);
            mTvTip.setTextColor(Color.RED);
        }
        mTvTip.setText(hintText);
        mIsConnected = isConnected;
    }

    /**
     * 显示主动连接蓝牙设备的进度对话框
     *
     * @param deviceName
     */
    private void showConnectProgressDialog(String deviceName) {

        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
        }
        mProgressDialog.setTitle("蓝牙串口");
        mProgressDialog.setMessage("正在与 " + deviceName + " 建立连接... ");
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mProgressDialog.show();
    }

    /**
     * 隐藏主动连接蓝牙设备的进度对话框
     */
    private void hideConnectProgressDialog() {

        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    /**
     * 显示 Toast 消息
     *
     * @param message
     */
    private void showToastMessage(String message) {

        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

    /**
     * 自定义蓝牙相关广播接收者
     */
    private class BluetoothReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            switch (action) {
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                    switch (state) {
                        case BluetoothAdapter.STATE_ON:
                            showToastMessage("蓝牙已打开");
                            Log.d(TAG, "蓝牙已开启");
                            // 2020/3/10 开启监听蓝牙连接
                            startAcceptTask();
                            mTvConnectState.setEnabled(true);
                            refreshConnectStatus(false, "蓝牙已开启");
                            break;
                        case BluetoothAdapter.STATE_OFF:
                            showToastMessage("蓝牙已关闭");
                            Log.d(TAG, "蓝牙已关闭");
                            mTvConnectState.setEnabled(false);
                            refreshConnectStatus(false, "蓝牙已关闭");
                            break;
                    }
                    break;
                case BluetoothDevice.ACTION_ACL_CONNECTED:
                    Log.d(TAG, "onReceive已连接: " + device.getName());
                    break;
                case BluetoothDevice.ACTION_ACL_DISCONNECTED:
                    Log.e(TAG, "onReceive已断开: " + device.getName());
                    break;
                default:
                    break;
            }
        }
    }
}
